package com.summer.function;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.function.Function;

public enum DateUtil {

	HHmm(new SimpleDateFormat("HH:mm")),
    yyyy_MM_dd(new SimpleDateFormat("yyyy-MM-dd")),
    yyyy_MM_dd_HHmmss(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    public final SimpleDateFormat dateFormat;

    DateUtil(SimpleDateFormat dateFormat) {
        this.dateFormat = dateFormat;
    }

    /**
     * 获取当前时间并格式化
     * @return 当前时间对于格式的字符串。
     */
    public String getCurrentTime() {
        return dateFormat.format(new Date());
    }

    /**
     * 计算某个时刻到今天的年数差
     * @param fromTime 指定时间
     * @return 年数差
     */
    public int calcYearsDifferenceToToday(long fromTime) {
        return calcDaysDifferenceToToday(fromTime) / 365;
    }

    /**
     * 计算某个时刻到今天的天数差
     * @param dateString 指定时间，字符串
     * @return 天数差
     */
    public int calcDaysDifferenceToToday(String dateString) {
        return calcDaysDifferenceToToday(parse(dateString));
    }

    /**
     * 计算某个时刻到今天的天数差
     * @param fromDate 指定时间 Date
     * @return 天数差
     */
    public int calcDaysDifferenceToToday(Date fromDate) {
        return calcDaysDifferenceToToday(fromDate.getTime());
    }

    /**
     * 计算某个时刻到今天的天数差
     * @param fromTime 指定时间 long
     * @return 天数差
     */
    public int calcDaysDifferenceToToday(long fromTime) {
        long unitDayToMs = (1000 * 60 * 60 * 24);
        // 修正不满1天的时间却在下一天的情况
        fromTime = (fromTime - (fromTime % unitDayToMs)) + 1;
        long timeDifference = calcTimeDifferenceToToday(fromTime);
        return (int) (timeDifference / unitDayToMs);  // 计算天
    }

    /**
     * 计算某个时刻到今天的时间差
     * @param fromTime 指定时间
     * @return 时间差
     */
    public long calcTimeDifferenceToToday(long fromTime) {
        long nowTime  = new Date().getTime();
        long unitDayToMs = (1000 * 60 * 60 * 24);
        // 修正不满1天的时间却在下一天的情况
        nowTime  = (nowTime  - (nowTime  % unitDayToMs)) + 1;

        return calcTimeDifference(fromTime, nowTime);
    }

    /**
     * 计算起止时间差
     * @param fromTime long 开始时间
     * @param toTime   long 终止时间
     * @return 时间差
     */
    public long calcTimeDifference(long fromTime, long toTime) {
        return toTime - fromTime;
    }

    public boolean assertToTodayValid(long fromTime, int limit, boolean isUnitDay) {
    	if(isUnitDay) {
    		return calcDaysDifferenceToToday(fromTime) < limit;
    	} else {
    		return calcTimeDifference(fromTime, new Date().getTime()) < limit;
    	}
    }
    public boolean assertToTodayValid(String fromTime, int limit, boolean isUnitDay) {
    	if(isUnitDay) {
    		return calcDaysDifferenceToToday(fromTime) < limit;
    	} else {
    		return calcTimeDifference(parse(fromTime).getTime(), new Date().getTime()) < limit;
    	}
    }


    /**
     * 解析字符串为Data类型
     * @param dataString 时间字符串
     * @return Date 时间
     */
    public Date parse(String dataString) {
        try {
            return dateFormat.parse(dataString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 格式化 date 为对应格式
     * @param date 时间
     * @return String 时间
     */
    public String format(Date date) {
        return dateFormat.format(date);
    }

    /**
     * 将一个符合当前格式的时间字符串转换成目标格式的时间字符串
     * @param dataString 时间字符串
     * @param dateUtil 目标格式
     * @return 期望的时间字符串
     */
    public String to(String dataString, DateUtil dateUtil) {
        String dateStr = dateUtil.format(parse(dataString));
        return dateStr;
    }

    private Function<Object, ?> transaction;

    private Object transaction(Object date) {
        if(date instanceof String) {
            return parse((String) date);
        }
        if(date instanceof Date) {
            return format((Date) date);
        }
        return date;
    }

    public DateUtil transaction(final DateUtil dateUtil) {
        Function<Object, ?> function = date -> dateUtil.transaction(date);
        transaction = transaction == null ? function : transaction.andThen(function);
        return this;
    }

    public <T,P> T runTransform(P date) {
        try {
            if(transaction != null) {
                return (T) transaction(transaction.apply(date));
            } else {
                return (T) transaction(date);
            }
        } finally {
            transaction = null;
        }
    }
    
    public static void main(String[] args) {
		Date s = DateUtil.HHmm
				.transaction(DateUtil.yyyy_MM_dd_HHmmss)
				.transaction(DateUtil.HHmm)
				.runTransform("2020-09-22 10:20:30");

		String ss = DateUtil.HHmm
				.transaction(DateUtil.yyyy_MM_dd_HHmmss)
				.runTransform("2020-09-22 10:20:30");
		
		String sss = DateUtil.HHmm
				.runTransform(new Date());
		
		
		String ssss = DateUtil.yyyy_MM_dd
				.runTransform(new Date());
		
		System.out.println(s);
		
		System.out.println(ss);
		
		System.out.println(sss);
		
		System.out.println(ssss);

		System.out.println(DateUtil.yyyy_MM_dd_HHmmss.to("2020-09-22 10:20:30", yyyy_MM_dd));
		System.out.println(DateUtil.yyyy_MM_dd.to("2020-09-22 10:20:30", yyyy_MM_dd_HHmmss)); 
		
		System.out.println(DateUtil.yyyy_MM_dd_HHmmss.assertToTodayValid("2020-09-29 16:27:30", 0, false));
		
		System.out.println(DateUtil.yyyy_MM_dd_HHmmss.assertToTodayValid("2020-09-23 16:27:30", 7, true));

	}

}
